<?php

/**
 * Description of Tag
 *
 * @author Andrea
 */
abstract class Tag {

    protected $anchestor;

    /**
     * @var array contains all the attributes of this tag.
     * Every key corresponds with attribute's name and points to its value.
     */
    protected $attributes = array ();
    protected $ids = array ();

    /**
     * @var string contains the name of this tag.
     */
    protected $name;
    protected $names = array ();
    protected $outerHTML = null;
    public $tags = array ();

    public function __construct ($name, $attributes = null, $outerHTML = null) {
        $this->anchestor = $this;
        $this->name = $name;
        /* Indexing tags */
        if ($this->anchestor) {
            $this->anchestor->tags[$name][] = $this;
        }
        $this->tags[$name][] = $this;
        if (isset ($attributes)) {
            /* Indexing name attribute */
            if (is_array ($attributes)) {
                if (isset ($attributes['name'])) {
                    $name_attr = $attributes['name'];
                    if ($name_attr == 'sesso')
                        if ($this->anchestor) {
                            $this->anchestor->names[$name_attr][] = $this;
                        }
                    $this->names[$name_attr][] = $this;
                }
                /* Indexing id */
                if (isset ($attributes['id'])) {
                    $id = $attributes['id'];
                    if ($this->anchestor) {
                        $this->anchestor->ids[$id][] = $this;
                    }
                    $this->anchestor->ids[$id][] = $this;
                }
            } else if (is_string ($attributes)) {
                $attributes = trim ($attributes);
                $attributes = explode (' ', $attributes);
                foreach ($attributes as $attribute) {
                    $attribute = explode ('=', $attribute, 2);
                    $attributes[$attribute[0]] = $attribute[1];
                }
            }
            $this->attributes = $attributes;
        }
        if (isset ($outerHTML) && is_a ($outerHTML, 'Tag')) {
            $this->outerHTML = $outerHTML;
        }
    }

    public function addAttribute ($attribute_name, $attribute_value) {
        $this->attributes[$attribute_name] = $attribute_value;
    }

    public function getAnchestor () {
        return $this->anchestor;
    }

    public function getAttribute ($name) {
        if (is_string ($name) && isset ($this->attributes[$name])) {
            return $this->attributes[$name];
        }
        return false;
    }

    /**
     * Returns an array containing the attributes of this tag.
     * @return array array containing the attributes.
     */
    public function getAttributes () {
        return $this->attributes;
    }

    public function getTagById ($id) {
        if (is_string ($id) && isset ($this->ids['id'])) {
            return $this->ids['id'];
        }
    }

    public function getTagByName ($name) {
        if (is_string ($name) && isset ($this->names[$name])) {
            return $this->names[$name];
        }
    }

    public function getTagsByTagName ($name) {
        if (is_string ($name) && isset ($this->tags[$name])) {
            return $this->tags[$name];
        } else {
            return false;
        }
    }

    public function getTagsNames () {
        return $this->names;
    }

    /**
     * Returns the name of this tag.
     * @return string name of this tag. 
     */
    public function getName () {
        return $this->name;
    }

    public function parseHTML ($html) {
        $arr = array ();
        if (is_a ($html, 'Tag')) {
            $arr[] = $html;
        } else if (is_array ($html)) {
            foreach ($html as $value) {
                $arr[] = $this->parseHTML ($value);
            }
        } else if (is_string ($html)) {
            do {
                if (is_integer ($l = strpos ($html, '<'))) {
                    if ($l > 0) {
                        $arr[] = substr ($html, 0, $l);
                        $html = substr ($html, $l);
                    }
                    $l = 1;
                    if (is_integer ($r = strpos ($html, '>'))) {
                        if (is_integer ($r_ = strpos ($html, '/>')) && $r_ < $r) {
                            $r = $r_;
                        }
                        $content = trim (substr ($html, $l, $r - $l));
                        $content = explode (' ', $content);
                        $name = $content[0];
                        if (count ($content) > 1) {
                            for ($i = 1; $i < count ($content); $i++) {
                                $attribute = explode ('=', $content[$i], 2);
                                $attributes[$attribute[0]] = trim ($attribute[1], '"');
                            }
                        } else {
                            $attributes = null;
                        } if (is_integer ($r_ = strpos ($html, '/>')) && $r_ < $r) {
                            $tag = new EmptyTag ($name, $attributes, $this);
                        } else {
                            $html = substr ($html, $r + 1);
                            if (is_integer ($r = strpos ($html, "</$name>"))) {
                                $innerHTML = substr ($html, 0, $r);
                            } else {
                                $innerHTML = null;
                            }
                            $html = trim (substr ($html, $r + 3 + strlen ($name)));
                            $tag = new FullTag ($name, $attributes, $innerHTML, $this);
                        }
                        $arr[] = $tag;
                    } else {
                        if (!empty ($html)) {
                            $arr[] = $html;
                        }
                        break;
                    }
                } else {
                    if (!empty ($html)) {
                        $arr[] = $html;
                    }
                    break;
                }
            } while (!empty ($html));
        }
        return $arr;
    }

    public function setName ($name) {
        if (is_string ($name)) {
            $this->name = $name;
            return true;
        } else {
            return false;
        }
    }

    /**
     * This method returns a partial representation of this tag
     * 
     * @return string 
     */
    public function __toString () {
        $str = "<$this->name ";
        if (is_array ($this->attributes)) {
            foreach ($this->attributes as $name => $value) {
                $str .= "$name=\"$value\" ";
            }
        } else if (is_string ($this->attributes)) {
            $str .= $this->attributes . ' ';
        }
        return $str;
    }

}

?>
